#! user/bin/python
# -*- coding: utf-8 -*-

"""
Created on 2021/8/19 15:58

@File: 多路复用选择服务器_select-server.py
@Author: LT
@Description: 服务器：使用select并行处理多个客户端。使用select模块手动在套接字之间多重通道传输：
              接收新的客户端连接的主套接字，并输入套接字连接刀接收的客户端；select可以采用可选的
              第四个参数0来进行轮询，用n.m来等待n.m秒，或者忽略直接等待直到任意套接字准备好了，可以处理。
"""
import sys, time
from select import select
from socket import socket, AF_INET, SOCK_STREAM
import time

myHost = ""
myPort = 50007
numPortSocks = 2

if len(sys.argv) == 3:
    myHost, myPort = sys.argv[1:]


def now():
    return time.ctime(time.time())


# make main sockets for accepting new client requests
mainsocks, readsocks, writesocks = [], [], []
for i in range(numPortSocks):
    portsock = socket(AF_INET, SOCK_STREAM)                                     # 创建一个TCP/IP协议的套接字实例
    portsock.bind((myHost, myPort))                                             # 绑定套接字到服务器端口号
    portsock.listen(5)

    mainsocks.append(portsock)                                                  # 添加到main list 中以甄别
    readsocks.append(portsock)                                                  # 添加到select输入列表中
    myPort += 1

# 事件循环：监听并多路复用直到服务器进程被终止
print('select-server loop starting...')
while True:
    # print(readsocks)
    readables, writeables, exceptions = select(readsocks,               # select指定三种列表，很像C语言的select——输入源
                                               writesocks,              # 输出源
                                               [],                      # 特殊条件源
                                               )                        # 还有一个可选的timeout，0意味着简单的轮询，省略意味着等待，直到至少有一个对象准备好
    for sockobj in readables:
        if sockobj in mainsocks:
            # port socket:接受一个新的客户端连接
            newsock, address = sockobj.accept()                                 # newsock是一个新的套接字
            print("Connect:", address, id(newsock))
            readsocks.append(newsock)                                           # 加到select列表，等待
        else:
            # client socket: read next line
            data = sockobj.recv(1024)
            print('\tgot', data, 'on', id(sockobj))
            if not data:
                sockobj.close()
                readsocks.remove(sockobj)                                       # 删除
            else:
                # 这里可能会阻塞：
                reply = "Echo=>%s at %s" % (data, now())
                sockobj.send(reply.encode())



